package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.base.ResponseResult;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.enums.DeviceLocationTypeEnum;
import com.zzyl.enums.DevicePhysicalLocationTypeEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliIoTConfigProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @Description DeviceServiceImpl
 * @Author shejunlian
 * @Date 2024-07-23
 */
@Service
@Slf4j
public class DeviceServiceImpl implements DeviceService {
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private Client client;

    @Autowired
    private AliIoTConfigProperties aliIoTConfigProperties;

    /**
     * 从物联网平台同步产品列表
     *
     * @return
     */
    @Override
    public void syncProductList() {
        QueryProductListRequest queryProductListRequest = new QueryProductListRequest();
        //分页条件
        queryProductListRequest.setPageSize(10);
        queryProductListRequest.setCurrentPage(1);
        //公共实列
        queryProductListRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        //查询公共实例下的原有产品
        QueryProductListResponse queryProductListResponse = null;

        try {
            queryProductListResponse = client.queryProductList(queryProductListRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_PRODUCT_ERROR);
        }
        //判断调用成功失败
        if (!queryProductListResponse.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.IOT_QUERY_PRODUCT_ERROR);
        }
        //调用成功
        List<QueryProductListResponseBody.QueryProductListResponseBodyDataListProductInfo> productInfoList =
                queryProductListResponse.getBody().getData().getList().getProductInfo();

        //将productInfoList拷贝到List<ProductVo>
        List<ProductVo> productVoList = BeanUtil.copyToList(productInfoList, ProductVo.class);

        //判断有效性
        if (ObjectUtil.isEmpty(productVoList)) {
            throw new RuntimeException("阿里云IOT还没有创建产品");
        }

        //写入缓存
        redisTemplate.opsForValue().set(CacheConstants.ALL_PRODUCT_KEY, JSONUtil.toJsonStr(productVoList));
    }

    /**
     * 查询所有产品列表
     *
     * @return
     */
    @Override
    public Object allProduct() {
        //1. 从缓存里面获取数据列表json字符串
        String json = redisTemplate.opsForValue().get(CacheConstants.ALL_PRODUCT_KEY).toString();

        //3. 将json转换为List<ProductVO>
        List<ProductVo> productVoList = JSONUtil.toList(json, ProductVo.class);

        //4. 返回数据
        return productVoList;
    }


    /**
     * 注册设备
     *
     * @param deviceVo
     * @return
     */
    @Autowired
    private DeviceMapper deviceMapper;

    @Override
    public ResponseResult<Void> registerDevice(DeviceDto deviceDto) {

        //1.根据设备名字查找数据库是否存在数据, 返回数量, 数量大于0表示存在
        Long count = deviceMapper.countByDeviceName(deviceDto.getDeviceDescription());
        if (count > 0) {
            throw new BaseException(BasicEnum.DEVICE_NAME_EXIST);
        }

        //2.调用阿里云IOT注册设备
        RegisterDeviceRequest registerDeviceRequest = deviceDto.getRegisterDeviceRequest();
        registerDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        RegisterDeviceResponse registerDeviceResponse = null;

        try {
            registerDeviceResponse = client.registerDevice(registerDeviceRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        if (!registerDeviceResponse.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        //获取响应数据设备id, 封装到deviceDto
        deviceDto.setIotId(registerDeviceResponse.getBody().getData().getIotId());

        //3.调用阿里云IOT查询所属产品名字
        QueryProductRequest queryProductRequest = new QueryProductRequest();
        queryProductRequest.setProductKey(deviceDto.getProductKey());
        queryProductRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryProductResponse queryProductResponse = null;

        try {
            queryProductResponse = client.queryProduct(queryProductRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        if (!queryProductResponse.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        //封装产品名字
        deviceDto.setProductName(queryProductResponse.getBody().getData().getProductName());
        //将DeviceDto赋值给Device
        Device device = BeanUtil.toBean(deviceDto, Device.class);

        //4.判断位置类型是否为0, 设置物理位置类型为-1
        if (device.getLocationType().equals(DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal())) {
            device.setPhysicalLocationType(DevicePhysicalLocationTypeEnum.ELDER.getOrdinal());
        }
        //设置门禁0
        device.setHaveEntranceGuard(0);

        //5.设备插入数据库
        try {
            deviceMapper.insert(device);
        } catch (Exception e) {
            e.printStackTrace();
            //6.插入发生异常, 调用阿里云IOT删除设备
            DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
            deleteDeviceRequest.setIotId(device.getIotId());
            deleteDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
            DeleteDeviceResponse deleteDeviceResponse = null;
            try {
                deleteDeviceResponse = client.deleteDevice(deleteDeviceRequest);
            } catch (Exception ex) {
                //插入到一个记录表中, 记录远程删除失败
                //发送短信响应IT管理员, 出现远程删除失败
                throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
            }
        }

        //7.返回数据
        return ResponseResult.success();
    }

    /**
     * 分页查询设备列表
     *
     * @param devicePageQueryDto
     * @return
     */
    @Override
    public PageResponse<DeviceVo> pageQueryDevice(DevicePageQueryDto devicePageQueryDto) {
        //设置PageHelper分页插件设置
        PageHelper.startPage(devicePageQueryDto.getPageNum(), devicePageQueryDto.getPageSize());

        //执行根据条件查询数据库列表数据
        Page<DeviceVo> voPage = deviceMapper.pageQueryDevice(devicePageQueryDto);

        //封装PageResponse<DeviceVo>返回
        return PageResponse.of(voPage, DeviceVo.class);
    }

    /**
     * 查询设备详细数据
     *
     * @param request
     * @return
     */
    @Override
    public ResponseResult<DeviceVo> queryDeviceDetail(QueryDeviceDetailRequest request) {

        //1.远程调用IOT接口QueryDeviceDetail, 获取到部分的设备详细数据
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryDeviceDetailResponse response = null;
        try {
            response = client.queryDeviceDetail(request);
        } catch (Exception e) {
            log.error("获取IOT设备详细数据失败, 原因:{}", e.getMessage());
        }
        if (!response.getBody().getSuccess()) {
            log.error("获取IOT设备详细数据失败");
        }
        QueryDeviceDetailResponseBody.QueryDeviceDetailResponseBodyData data = response.getBody().getData();

        //2.根据设备id查询数据库获取设备信息DeviceVo
        DeviceVo deviceVo = deviceMapper.selectByIoId(request.getIotId());

        //3.两部分IOT设备数据和查询数据库的数据合并
        // BeanUtil.copyProperties(data,deviceVo); //如果data里面有null, 那会给deviceVo对应属性也设置为null
        BeanUtil.copyProperties(data, deviceVo, CopyOptions.create().ignoreNullValue());//如果data里面属性值为null的属性不用赋值给deviceVo
        //4.返回数据
        return ResponseResult.success(deviceVo);
    }

    /**
     * 查看指定产品的已发布物模型中的功能定义详情
     *
     * @param request
     * @return
     */
    @Override
    public ResponseResult queryThingModelPublished(QueryThingModelPublishedRequest request) {
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryThingModelPublishedResponse response = null;

        try {
            response = client.queryThingModelPublished(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_THING_MODEL_PUBLISHED_ERROR);
        }
        return ResponseResult.success(response.getBody().getData());
    }

    /**
     * 查询指定设备的物模型运行状态
     *
     * @param request
     * @return
     */
    @Override
    public ResponseResult queryDevicePropertyStatus(QueryDevicePropertyStatusRequest request) {
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryDevicePropertyStatusResponse response;
        try {
            response = client.queryDevicePropertyStatus(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }
        return ResponseResult.success(response.getBody().getData());
    }

    /**
     * 删除设备
     *
     * @param deviceRequest
     * @return
     */
    @Override
    public void deleteDevice(DeleteDeviceRequest deviceRequest) {
        deviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());

        DeleteDeviceResponse response;

        try {
            response = client.deleteDevice(deviceRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }
        if (Boolean.TRUE.equals(response.getBody().getSuccess())) {
            deviceMapper.deleteDevice(deviceRequest.getIotId());
            return;
        }

        throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
    }

    /**
     * 修改设备备注名称
     *
     * @param deviceDto
     * @return
     */
    @Override
    public void updateDevice(DeviceDto deviceDto) {
        //1.首先看数据库是否有设备
        Device device = deviceMapper.selectByKey(deviceDto.getId());
        if (com.zzyl.utils.ObjectUtil.isEmpty(device)){
            throw new BaseException(BasicEnum.DEVICE_NOT_EXIST);//  DEVICE_NOT_EXIST(1514, "该设备不存在，无法修改"),
        }

        //2.调用物联网接口 更新云服务信息
        BatchUpdateDeviceNicknameRequest budnr = new BatchUpdateDeviceNicknameRequest();
        budnr.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo info = BeanUtil
                .toBean(deviceDto, BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo.class);
        budnr.setDeviceNicknameInfo(Lists.newArrayList(info));
        BatchUpdateDeviceNicknameResponse response;

        try {
            response = client.batchUpdateDeviceNickname(budnr);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }
        if (com.zzyl.utils.ObjectUtil.notEqual(Boolean.TRUE,response.getBody().getSuccess())){
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }

        //3.保存位置
        Device device1 = BeanUtil.toBean(deviceDto, Device.class);
        //如果是随身设备, 物理位置设为-1
        if (device1.getLocationType().equals(DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal())){
            device1.setPhysicalLocationType(DevicePhysicalLocationTypeEnum.ELDER.getOrdinal());
        }

        //更新数据库中的设备信息
        try {
            deviceMapper.updateByPrimaryKeySelective(device1);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.RE_SELECT_PRODUCT);
        }

    }
}
